
"""
    pyprosim - a simple prolog compiler developed to PCS2056 course (Compilers) at Poli-USP\
    Copyright (C) 2008 Rodrigo Rodrigues da Silva

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
"""

from pyprosim.token import *
from pycoopiler.enum import enum

class tokenizer:
    
    states = enum("START INF NOME NUM OP_AND OP_OR OP_NOT ABRE_P FECHA_P VINCULO META VIRGULA")
    
    def __init__(self, file):
        self._file = file
        self.reading = ''
        self.current_char = ''
        self.current = None
        self.next_char()
        self.next_token()
        
    def next_char(self):
        if not self.current_char.isspace():
            self.reading += self.current_char
        self.current_char = self._file.read(1)
        
    def ret_token(self, type):
        self.current = token(self.reading, type)
        return self.current
        
    def current(self):
        return self.current
      
    def next_token(self):
        self.state = self.states.START
        self.reading = ''
        
        while True:            
            
            if self.state == self.states.START:
                
                if self.current_char.isdigit():
                    self.state = self.states.NUM
                    self.next_char()
                    
                elif self.current_char.islower():
                    self.state = self.states.NOME
                    self.next_char()
                    
                elif self.current_char.isupper():
                    self.state = self.states.INF
                    self.next_char()
                    
                elif self.current_char == '?':
                    self.state = self.states.META
                    self.next_char()
                    
                elif self.current_char == ':':
                    self.state = self.states.VINCULO
                    self.next_char()
                    
                elif self.current_char == '(':
                    self.next_char()
                    return self.ret_token(token.types.ABRE_P)
                
                elif self.current_char == ')':
                    self.next_char()
                    return self.ret_token(token.types.FECHA_P)
                
                elif self.current_char == '&':
                    self.next_char()
                    return self.ret_token(token.types.OP_AND)
                
                elif self.current_char == ',':
                    self.next_char()
                    return self.ret_token(token.types.VIRGULA)
            
                elif self.current_char == '':
                    return self.ret_token(token.types.EOF)
                
                elif not self.current_char.isspace():
                    raise Exception("ERRO: caractere invalido!")
                
                else: 
                    self.next_char()
            
            elif self.state == self.states.NUM:
                if self.current_char.isdigit():
                    self.next_char()
                else:
                    type = token.types.NUM
                    return self.ret_token(type)

            elif self.state == self.states.NOME:
                if self.current_char.isalnum():
                    self.next_char()
                else:
                    if self.reading == "not" : type =  token.types.OP_NOT
                    elif self.reading == "or" : type =  token.types.OP_OR
                    else: type = token.types.NOME
                    return self.ret_token(type)
                
            elif self.state == self.states.INF:
                if self.current_char.isalnum():
                    self.next_char()
                else:
                    type = token.types.INF
                    return self.ret_token(type)
                
            elif self.state == self.states.META:
                if self.current_char == '-':
                    self.next_char()
                    return self.ret_token(token.types.META)
                else: raise Exception ("Invalid state!")
            
            elif self.state == self.states.VINCULO:
                if self.current_char == '-':
                    self.next_char()
                    return self.ret_token(token.types.VINCULO)
                else: raise Exception ("Invalid state!")
            
            else: raise Exception("ERRO: Estado invalido: " + self.state)